import CryptoJS from 'crypto-js'
import XEUtils from 'xe-utils'
import {SM2, SM3, SM4} from 'gm-crypto'
// SHA256
const sha256 = (data) => {
  return CryptoJS.SHA256(data).toString()
}
// MD5
export const md5 = (data) => {
  return CryptoJS.MD5(data).toString()
}

const getNonce = () => {
  return Math.random().toString(36).substring(2)
}

/**
 * 接口参数签名
 * @param {*} config 请求配置
 * @param apiKey
 * @param secretKey
 * @param signType
 */
export const sign = (config, apiKey, secretKey, signType) => {
  // 获取到秒级的时间戳,与后端对应
  let data = {
    ApiKey: apiKey,
    Timestamp: XEUtils.toDateString(new Date(), 'yyyyMMddHHmmss'),
    SignType: signType,
    Nonce: getNonce()
  }

  const SING_KEY = 'Sign'
  const SECRET_KEY = 'SecretKey'
  let keys = []
  if (config.method === 'get') {
    // url参数签名
    data = config.params = Object.assign(config.params ? config.params : {}, data)
    keys = Object.keys(data)
  } else {
    // request body参数的内容
    data = config.data = Object.assign(config.data ? config.data : {}, data)
    keys = Object.keys(data)
  }
  // 排序
  const skeys = keys.sort()
  let str = ''
  skeys.filter(k => {
    return k !== SING_KEY && k !== SECRET_KEY
  }).filter(k => {
    return !(XEUtils.isArray(data[k]) && data[k].length === 0)
  }).filter(k => {
    return !XEUtils.isNull(data[k])
  }).map(k => {
    const v = data[k]
    // 参数值为空，则不参与签名
    str = str + k + '=' + v + '&'
  })
  console.log(str)
  str = str + SECRET_KEY + '=' + secretKey
  let sign = ''
  if (data.SignType === 'MD5') {
    sign = md5(str)
  }
  if (data.SignType === 'SHA256') {
    sign = sha256(str)
  }
  if (config.method === 'get') {
    config.params[SING_KEY] = sign
  } else {
    config.data[SING_KEY] = sign
  }
  return config
}

/**
 * 国密加密
 * @param {*} config 请求配置
 * @param secret
 * @param secretKey
 */
export const signatureGenerate = (config, secret, secretKey) => {
  const {url, data, params} = config
  // 是否需要加密
  const cryptoEnabled = JSON.parse(process.env.VUE_APP_CRYPTO_ENANLED) && config?.headers?.cryptoEnabled === 'true'

  if (typeof data === 'object' && cryptoEnabled) {
    config.data = {cryptoStr: encryptSM2(JSON.stringify(data), secretKey)}
  }
  if (typeof params === 'string' && cryptoEnabled) {
    config.params = {cryptoStr: encryptSM2(JSON.stringify(JSON.parse(params)), secretKey)}
  }

  let dataStr = ''
  if (params && params.length) {
    dataStr = JSON.stringify(sortAescParams(params))
  }
  if (data) {
    dataStr = JSON.stringify(sortAesc(data))
  }

  // 时间戳
  let timestamp = new Date().getTime()
  // 生成签名
  let str = dataStr + "&secret=" + secret + "&timestamp=" + timestamp;
  const signature = JSON.parse(process.env.VUE_APP_SIGN_ENANLED) ? SM3.digest(str, 'utf8', 'hex').toUpperCase() : ''

  const dataSign = SM3.digest(url + dataStr, 'utf8', 'hex')
  return {signature, timestamp, dataSign: dataSign}
}

// SM2加密
const encryptSM2 = (data, secretKey) => {
  try {
    return SM2.encrypt(data, secretKey, {
      inputEncoding: 'utf8',
      outputEncoding: 'hex'
    })
  } catch (e) {
    console.error("加密异常：", e)
    return data
  }
}
// SM2解密
export const decryptSM2 = (data, secretKey) => {
  try {
    return SM2.decrypt(data, secretKey, {
      inputEncoding: 'hex',
      outputEncoding: 'utf8'
    })
  } catch (e) {
    console.error("解析异常：", e)
    return data
  }
}

const sortAesc = (obj) => {
  const sortObj = {};
  Object.keys(obj).sort().forEach(item => {
    let itemOjb = obj[item];
    if (itemOjb != null && itemOjb != undefined) {
      if (itemOjb instanceof Array) {
        let arrChild = [];
        itemOjb.forEach((index) => {
          if (index.constructor === Object) {
            let Objarr = sortAesc(index);
            arrChild.push(Objarr);
          } else {
            arrChild.push(index);
          }
        });
        sortObj[item] = arrChild;
      } else if (itemOjb.constructor === Object) {
        if (itemOjb != null && itemOjb != undefined) {
          sortObj[item] = sortAesc(itemOjb);
        }
      } else {
        sortObj[item] = itemOjb;
      }
    }
  })
  return sortObj;
}

const sortAescParams = (obj) => {
  const sortObj = {};
  Object.keys(obj).sort().forEach(item => {
    let itemOjb = obj[item];
    if (itemOjb != null && itemOjb != undefined) {
      if (typeof itemOjb == 'string') {
        sortObj[item] = itemOjb
      } else {
        sortObj[item] = JSON.stringify(itemOjb);
      }
    }
  })
  return sortObj;
}


